#define _CRT_SECURE_NO_WARNINGS 1

// 操作符详解 

// 2进制换8进制的时候，右边向左每3个2进制会换算一个8进制位
// 2进制换16进制的时候，右边向左每4个2进制会换算成一个16进制位

// 整数的2进制表示方法有三种：原码、反码、补码
// 正整数的原、反、补码都相同
// 负整数的三种表示方法各不相同

// 原码将数值按照正负数形式翻译成二进制得到的就是原码
// 将原码的符号位不变，其他位依次按位取反就可以得到反码
// 补码，反码+1就得到补码 ；另外，反码得到原码也是可以使用取反+1的操作
// 对于整形来说，数据存放内存中其实存放的是补码

// 在计算机系统中，数值一律用补码来表示和存储。原因在于，使用补码，可以将符号位和数值域统一处理
// 加法和减法也能统一处理（CPU只有加法器）
//00000000000000000000000000000001   ---> 1的补码
//10000000000000000000000000000001
//11111111111111111111111111111110
//11111111111111111111111111111111 ----> -1的补码
//00000000000000000000000000000001
//00000000000000000000000000000000 ---> 0

//#include <stdio.h>
//
//int main()
//{
//	//	int num = 10;  //signed int num = 10;
//	//10是存放在整型变量num中，占4个字节 == 32bit位
//	//00000000000000000000000000001010  - 原码	
//	//00000000000000000000000000001010  - 反码
//	//00000000000000000000000000001010  - 补码
//
//	//	int num2 = -10;
//	//-10是存放在整型变量num2中，占4个字节 == 32bit位
//	//10000000000000000000000000001010  - 原码
//	//11111111111111111111111111110101  - 反码
//	//11111111111111111111111111110110  - 补码
//
//	
//
//	return 0;
//}

// 右移分为两种，一种是逻辑右移，一种是算术右移
// 这取决于编译器的实现，大部分是算术右移，即左边用原该值的符号位填充，右边丢弃

//#include <stdio.h>
//
//int main()
//{
//	int m = 10;
//	int n = m >> 1;
//
//	// -10的原码
//	// 10000000000000000000000000001010
//
//	printf("m = %d\n", m);
//	printf("n = %d\n", n);
//
//	return 0;
//}

// 位操作符有：
// & ：按位与
// | ：按位或
// ^ : 按位异或
// ~ ：按位取反

// 如何不创建临时变量，实现两个整数的交换？
//#include <stdio.h>
//
//int main()
//{
//	// a = a + b;
//	// b = a - b;
//	// a = a - b;
//	// 这种写法的缺陷是：a和b如果非常大，求和后的结果超过了整形的最大值
//
//	return 0;
//}

// 异或操作符的特点：
// 1.a ^ a = 0
// 2.0 ^ a = a

// 因此，还可以使用这种方法
//#include <stdio.h>
//
//int main()
//{
//	int a = 3;
//	int b = 5;
//
//	a = a ^ b;
//	b = a ^ b;
//	a = a ^ b;
//
//	printf("a = %d\n", a);
//	printf("b = %d\n", b);
//
//	return 0;
//}

// 求一个整数存储在内存中的二进制中1的个数
// a & 1 == 1,就说明a的二进制中最低位是1
// a & 1 == 0,就说明a的二进制中最低位是0
// 内存中存储的都是补码，移动的也是补码

//#include <stdio.h>
//
//int main()
//{
//	int a = 10, count = 0;
//
//	for (int i = 0; i < 32; i++) {
//		if (((a >> i) & 1) == 1) 
//			count++;
//	}
//
//	printf("%d\n", count);
//
//	return 0;
//}

//#include <stdio.h>
//
//int count_one_bit(unsigned int num)
//{
//	int count = 0;
//
//	while (num) {
//		if (num % 2 == 1)
//			count++;
//		num /= 2;
//	}
//
//	return count;
//}
//
//int main()
//{
//	int num = -1;
//
//	//求一个整数存储在内存中的二进制中1的个数
//	//这种情况负数就会有问题，要unsigned int
//	int n = count_one_bit(num);
//	printf("%d\n", n);
//
//	return 0;
//}

// n = n & (n - 1)
// 效果是把n的二进制中最右边的1去掉了

// 因此，判断一个数是否是2的次方数
//#include <stdio.h>
//
//int main()
//{
//	int n;
//	scanf("%d", &n);
//
//	if (!(n & (n - 1))) printf("Yes\n");
//	else printf("No\n");
//
//	return 0;
//}

// 二进制位置0或者置1
//#include <stdio.h>
//
//int main()
//{
//	int n = 13;
//
//	n = n | (1 << 4);
//	printf("%d\n", n);
//
//	n = n & ~(1 << 4);
//	printf("%d\n", n);
//
//	return 0;
//}
// 二进制的相关操作，在单片机、嵌入式程序非常常见

// 逗号表达式，从左到右依次执行，整个表达式的结果是最后一个表达式的结果
//a = get_val();
//count_val(a);
//while (a > 0) {
//	// 业务处理
//	a = get_val();
//	count_val(a);
//}

//while (a = get_val(), count_val(a), a > 0) {
//	// 业务处理
//}

// sizeof是操作符!!!